
//
// 101210 - AH - Created.
// 101228 - AH - Minor java doc fix, bug discovered by java doc compiler.
// 110121a- AH - (Bien) getIndexOf(T[], T).
// 110121b- AH - (Bien) reverse(List<E>).
// 110217 - AH - (Bien) getLines(String).
// 110411 - AH - contains(T[], Object).
// 110425 - AH - (Garage) E_OBJECT_A.
// 120228 - AH - Moved from org.soekrat.engine. 
//

package org.soekrat.engine.util;

import static java.lang.Math.abs;

import java.io.BufferedReader;
import java.io.CharArrayReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.Random;

/**
 * <p>
 *   Utility methods and constants.
 * </p>
 * @author Arne Halvorsen (AH)
 * @author Laetitia Le Chatton (LLC) 
 */
public final class Util 
{
  private Util(){} // Utility pattern dictates private constructor.
  
  /**
   * <p>
   *   Tells if reasonable to say two {@code float}s are the same.
   * </p>
   * @param a One number.
   * @param b Other number.
   * @return {@code true} if to be regarded as the same, {@code false} if not.
   */
  public static boolean same(double a, double b){ return abs(a-b)<1e-6f; }
  
  /**
   * <p>
   *   Tells if reasonable to say two {@code float}s are the same.
   * </p>
   * @param a One number.
   * @param b Other number.
   * @return {@code true} if to be regarded as the same, {@code false} if not.
   */
  public static boolean same(float a, float b){ return abs(a-b)<1e-6f; }
  
  /**
   * <p>
   *   Selects a random element in an array.
   * </p>
   * @param <T> Content type.
   * @param a   Array.
   * @return Random element or {@code null} if {@code a} is empty.
   */
  public static <T> T getRandom(T[] a)
  {
    if (a==null)
    {
      throw new NullPointerException("a");
    }
    
    int n=a.length;
    switch (n)
    {
      case 0 : return null;
      case 1 : return a[0];
      default :
      {
        Random rnd=new Random();
        return a[rnd.nextInt(n)];
      }
    }
  }
  
  /**
   * <p>
   *   Selects a random element in a list.
   * </p>
   * @param <T> Content type.
   * @param l   List.
   * @return Random element or {@code null} if {@code l} is empty.
   */
  public static <T> T getRandom(List<T> l)
  {
    if (l==null)
    {
      throw new NullPointerException("l");
    }
    
    int n=l.size();
    switch (n)
    {
      case 0 : return null;
      case 1 : return l.get(0);
      default :
      {
        Random rnd=new Random();
        return l.get(rnd.nextInt(n));
      }
    }
  }
  
  /**
   * <p>
   *   Gets the index of an element in an array.
   * </p>
   * @param <T> Content type.
   * @param a   Array.
   * @param e   Element, may be {@code null}.
   * @return Index or {@code -1} if not found.
   */
  public static <T> int getIndexOf(T[] a, T e)
  {
    if (a==null)
    {
      throw new NullPointerException("a");
    }
    
    int n=a.length;
    for (int i=0; i<n; i++) if (a[i]==e) return i;
    return -1;
  }
 
  /**
   * <p>
   *   Produces the reverse list of a given list.
   * </p>
   * @param <E>  Content type.
   * @param list List to reverse.
   * @return Reversed list.
   */
  public static <E> List<E> reverse(List<E> list)
  {
    if (list==null)
    {
      throw new NullPointerException("list");
    }
    
    List<E> retVal=new ArrayList<E>();
    
    ListIterator<E> i=list.listIterator(list.size());
    while (i.hasPrevious())
    {
      retVal.add(i.previous());
    }
    
    return retVal;
  }
  
  /**
   * <p>
   *   Gets non blank lines of some text.
   * </p>
   * @param text Text to get lines of.
   * @return Lines.
   */
  public static List<String> getLines(String text)
  {
    if (text==null)
    {
      throw new NullPointerException("text");
    }
    
    try
    {
      List<String> retVal=new ArrayList<String>();

      CharArrayReader car=new CharArrayReader(text.toCharArray());
      BufferedReader br=new BufferedReader(car);
      String line=br.readLine();
      while (line!=null)
      {
        line=line.trim();
        if (line.length()!=0) retVal.add(line);
        line=br.readLine();
      }
      return retVal;
    }
    catch (IOException _){ throw new Error(); }
  }
  
  /**
   * <p>
   *   Tells if array contains element.
   * </p>
   * @param <T> Content type of array.
   * @param a   Array. If is {@code null} returns {@code false} and if is not
   *            {@code null} may contain {@code null} values.
   * @param v   Value to see if {@code a] contains, may be {@code null}.
   * @return {@code true} if {@code a} contains {@code v}.
   */
  public static <T> boolean contains(T[] a, Object v)
  {
    if (a==null) return false;
    for (T e : a) if (v==e || v.equals(e)) return true;
    return false;
  }
  
  /**
   * <p>
   *   The empty 
   *   {@code String} array shared.
   * </p>
   */
  public final static String[] E_STRING_A=new String[0];
  
  /**
   * <p>
   *   The empty 
   *   {@code Object} array shared.
   * </p>
   */
  public final static Object[] E_OBJECT_A=new Object[0];
 
}
